package com.amt.olcacon.service.impl;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import com.amt.olcacon.bo.*;
import com.amt.olcacon.db.DerbyConfig;
import com.amt.olcacon.entity.*;
import com.amt.olcacon.mapper.*;
import com.amt.olcacon.service.IProductProcessService;
import com.amt.olcacon.utils.ExcelParserTwoTables;
import com.amt.olcacon.utils.ExcelParserTwoTablesAllSheet;
import com.amt.olcacon.utils.Snowflake16Bit;
import com.amt.olcacon.vo.GlobalResponse;
import com.amt.olcacon.vo.request.ExchangeRequest;
import com.amt.olcacon.vo.request.FlowRequest;
import com.amt.olcacon.vo.request.FlowRequestList;
import com.amt.olcacon.vo.request.ProcessRequest;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.micrometer.common.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.openlca.core.DataDir;
import org.openlca.core.database.*;
import org.openlca.core.model.*;
import org.openlca.core.model.Process;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ProductProcessServiceImpl extends ServiceImpl<ProductProcessMapper, ProductProcessEntity> implements IProductProcessService {

    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private ProductFlowMapper productFlowMapper;

    @Autowired
    private ProductFlowPropertyMapper productFlowPropertyMapper;

    @Autowired
    private ProductFlowTypeMapper productFlowTypeMapper;

    @Autowired
    private ProductProcessMapper productProcessMapper;

    @Autowired
    private ProductExchangeMapper productExchangeMapper;

    @Autowired
    private TaskReportMapper  taskReportMapper;

    @Autowired
    private TaskMapper taskMapper;

    @Autowired
    private ExcelParserTwoTables excelParserTwoTables;

    @Autowired
    private ExcelParserTwoTablesAllSheet excelParserTwoTablesAllSheet;

    @Override
    public GlobalResponse<Boolean> importExcel(String filePath, String currentUser) throws IOException {
        var db = DataDir.get().openDatabase(DerbyConfig.DBNAME);

        FileData fileData = excelParserTwoTables.getFileData(filePath);
        Map<String, String> products = fileData.getProduct();
        List<Map<String, String>> exchanges = fileData.getExchange();

        String processName = products.get("process_name").trim();
        String productName = products.get("product_name").trim();
        String location = products.get("location").trim();
        String description = products.get("description").trim();
        Long productId = null;
        // 查询或创建产品
        if(StringUtils.isNotBlank(productName)){
            productId = getOrCreateProductByName(productName, currentUser);
        }

        // 获取主产品信息,(主产品单独插入，其余的副产品、输出、输入在下方batchInsertProductExchanges中插入)
        Map<String, String> mainProduct = exchanges.stream()
                .filter(exchange -> "主产品".equals(exchange.get("type")))
                .findFirst()
                .orElse(new HashMap<>());

        String mainProductName = mainProduct.get("name");
        Long type = getProductFlowTypeIdByName(mainProduct.get("category").trim());
        FlowProperty flowProperty = new FlowPropertyDao(db).getForName(mainProduct.get("unit_group")).getFirst();
        long flowPropertyId = flowProperty.id;
        Long locationId = null;
        if(null!= location){
            locationId = productProcessMapper.getGlobalRegions( mainProduct.get("location_code"));
        }
        long flowId = getOrCreateProductFlow(mainProductName, type, locationId, mainProduct.get("number"), flowPropertyId, currentUser);

        // 创建工序
        ProductProcessEntity productProcess = createProductProcess(processName, productId, flowId, locationId, description, currentUser);

        // 组装主产品 exchange
        List<ProductExchangeEntity> exchangeEntityList = new ArrayList<>();
        exchangeEntityList.add(getExchangeData(productProcess.getId(), mainProduct, currentUser));

        // 处理其他输入/输出项
        for (Map<String, String> flow : exchanges) {
            if (!"主产品".equals(flow.get("type"))) {
                exchangeEntityList.add(getExchangeData(productProcess.getId(), flow, currentUser));
            }
        }

        exchangeEntityList.forEach(exchangeEntity -> {
            log.info("正在处理 exchange 数据: {}", JSONUtil.toJsonStr(exchangeEntity));
        });
        // 批量插入 exchange 数据
        batchInsertProductExchanges(exchangeEntityList);

        return GlobalResponse.of(true);
    }

    @Override
    public GlobalResponse<Boolean> importExcelBatch(String filePath, String currentUser) throws IOException {
        var db = DataDir.get().openDatabase(DerbyConfig.DBNAME);

        List<FileData> fileDataList = excelParserTwoTablesAllSheet.getFileData(filePath);
        fileDataList.forEach(fileData -> {
            Map<String, String> products = fileData.getProduct();
            List<Map<String, String>> exchanges = fileData.getExchange();

            String processName = products.get("process_name").trim();
            String productName = products.get("product_name").trim();
            String location = products.get("location").trim();
            String description = products.get("description").trim();
            Long productId = null;
            // 查询或创建产品
            if(StringUtils.isNotBlank(productName)){
                productId = getOrCreateProductByName(productName, currentUser);
            }

            // 获取主产品信息,(主产品单独插入，其余的副产品、输出、输入在下方batchInsertProductExchanges中插入)
            Map<String, String> mainProduct = exchanges.stream()
                    .filter(exchange -> "主产品".equals(exchange.get("type")))
                    .findFirst()
                    .orElse(new HashMap<>());

            String mainProductName = mainProduct.get("name");
            Long type = getProductFlowTypeIdByName(mainProduct.get("category").trim());
            FlowProperty flowProperty = new FlowPropertyDao(db).getForName(mainProduct.get("unit_group")).getFirst();
            long flowPropertyId = flowProperty.id;
            Long locationId = null;
            if(null!= location){
                locationId = productProcessMapper.getGlobalRegions( mainProduct.get("location_code"));
            }
            long flowId = getOrCreateProductFlow(mainProductName, type, locationId, mainProduct.get("number"), flowPropertyId, currentUser);

            // 创建工序
            ProductProcessEntity productProcess = createProductProcess(processName, productId, flowId, locationId, description, currentUser);

            // 组装主产品 exchange
            List<ProductExchangeEntity> exchangeEntityList = new ArrayList<>();
            exchangeEntityList.add(getExchangeData(productProcess.getId(), mainProduct, currentUser));

            // 处理其他输入/输出项
            for (Map<String, String> flow : exchanges) {
                if (!"主产品".equals(flow.get("type"))) {
                    exchangeEntityList.add(getExchangeData(productProcess.getId(), flow, currentUser));
                }
            }

            exchangeEntityList.forEach(exchangeEntity -> {
                log.info("正在处理 exchange 数据: {}", JSONUtil.toJsonStr(exchangeEntity));
            });
            // 批量插入 exchange 数据
            batchInsertProductExchanges(exchangeEntityList);
        });


        return GlobalResponse.of(true);
    }

    @Override
    public GlobalResponse<String> checkExcelData(String filePath) {
        try {
            // 解析Excel文件
            FileData fileData = excelParserTwoTables.getFileData(filePath);
            List<Map<String, String>> exchanges = fileData.getExchange();
            Map<String, String> products = fileData.getProduct();

            // 存储错误信息
            List<String> errors = new ArrayList<>();

            // 校验规则1：在所有数据中 type为主产品的必须有且只能有一个
            long mainProductCount = exchanges.stream()
                    .filter(exchange -> "主产品".equals(exchange.get("type")))
                    .count();

            if(isBlank(products.get("process_name"))){
                errors.add("<span style='color:red;'>工序不能为空！</span>");
            }

            if (mainProductCount != 1) {
                errors.add("<span style='color:red;'>主产品必须有且只能有一个，当前找到 " + mainProductCount + " 个</span>");
            }

            // 遍历所有exchange数据进行校验
            for (Map<String, String> exchange : exchanges) {
                // 获取关键字段值用于错误信息展示
                String ioType = getValueOrDefault(exchange, "io_type");
                String source = getValueOrDefault(exchange, "source");
                String name = getValueOrDefault(exchange, "name");

                // 构建标识信息
                String identifier = String.format("[<span style='color:#0066cc;'>输入输出类型: %s</span>, <span style='color:#0066cc;'>来源: %s</span>, <span style='color:#0066cc;'>名称: %s</span>]",
                    ioType, source, name);

                // 校验规则3：io_type、source、name必填
                if (isBlank(exchange.get("io_type"))) {
                    errors.add(identifier + " <span style='color:red;'>*输入输出类型不能为空</span>");
                }
                if (isBlank(exchange.get("source"))) {
                    errors.add(identifier + " <span style='color:red;'>*来源不能为空</span>");
                }
                if (isBlank(exchange.get("name"))) {
                    errors.add(identifier + " <span style='color:red;'>*名称不能为空</span>");
                }

                // 校验规则2：如果io_type为产品时，type和allocation_factor必填
                if ("产品".equals(exchange.get("io_type"))) {
                    if (isBlank(exchange.get("type"))) {
                        errors.add(identifier + " <span style='color:red;'>*类型不能为空</span>");
                    }
                    if (isBlank(exchange.get("allocation_factor"))) {
                        errors.add(identifier + " <span style='color:red;'>*分配系数不能为空</span>");
                    } else {
                        // 校验分配系数是否为有效数字且在0-1范围内
                        try {
                            BigDecimal factor = new BigDecimal(exchange.get("allocation_factor"));
                            if (factor.compareTo(BigDecimal.ZERO) < 0 || factor.compareTo(BigDecimal.ONE) > 0) {
                                errors.add(identifier + " <span style='color:red;'>*分配系数必须在0-1之间</span>");
                            }
                        } catch (NumberFormatException e) {
                            errors.add(identifier + " <span style='color:red;'>*分配系数必须为有效数字</span>");
                        }
                    }
                }

                // 校验规则4：如果source为背景数据集那么environmental_flow_category必填
                if ("背景数据集".equals(exchange.get("source"))) {
                    if (isBlank(exchange.get("environmental_flow_category"))) {
                        errors.add(identifier + " <span style='color:red;'>环境流分类不能为空</span>");
                    }
                }

                // 校验规则5：如果source为用户数据库那么unit_group必填
                if ("用户数据库".equals(exchange.get("source"))) {
                    if (isBlank(exchange.get("unit_group"))) {
                        errors.add(identifier + " <span style='color:red;'>*单位组（英文）不能为空</span>");
                    }
                }

                // 校验规则6：如果category为物料那么number必填
                if ("物料".equals(exchange.get("category"))) {
                    if (isBlank(exchange.get("number"))) {
                        errors.add(identifier + " <span style='color:red;'>编号不能为空</span>");
                    }
                }

                // 校验规则7：如果upstream_type为背景数据集那么background_name、country_code必填
                if ("背景数据集".equals(exchange.get("upstream_type"))) {
                    if (isBlank(exchange.get("background_name"))) {
                        errors.add(identifier + " <span style='color:red;'>*背景数据名称不能为空</span>");
                    }
                    if (isBlank(exchange.get("country_code"))) {
                        errors.add(identifier + " <span style='color:red;'>*国家/地区（英文简写）不能为空</span>");
                    }
                }

                // 校验规则8：如果upstream_type为系统已有工序那么process_name、product_name必填
                if ("系统已有工序".equals(exchange.get("upstream_type"))) {
                    if (isBlank(exchange.get("process_name"))) {
                        errors.add(identifier + " <span style='color:red;'>*工序名称不能为空</span>");
                    }
//                    if (isBlank(exchange.get("product_name"))) {
//                        errors.add(identifier + " <span style='color:red;'>*所属产品不能为空</span>");
//                    }
                }
            }

            // 构建返回结果
            if (errors.isEmpty()) {
                return GlobalResponse.of("校验通过");
            } else {
//                    StringBuilder errorMsg = new StringBuilder("<span style='font-weight:bold;'>"+"数据校验失败，共发现 " + errors.size() + " 个错误:</span>\n");
                    StringBuilder errorMsg = new StringBuilder();
                for (int i = 0; i < errors.size(); i++) {
                    errorMsg.append((i + 1)).append(". ").append(errors.get(i)).append("\n");
                }
                return GlobalResponse.error(errorMsg.toString());
            }
        } catch (Exception e) {
            log.error("校验Excel数据时发生错误，文件路径: {}", filePath, e);
            return GlobalResponse.error("校验失败: " + e.getMessage());
        }
    }

    /**
     * 获取Map中的值，如果为空则返回"空"字符串
     * @param map Map对象
     * @param key 键
     * @return 值或"空"
     */
    private String getValueOrDefault(Map<String, String> map, String key) {
        String value = map.get(key);
        return isBlank(value) ? "空" : value;
    }

    /**
     * 判断字符串是否为空白
     * @param str 字符串
     * @return 是否为空白
     */
    private boolean isBlank(String str) {
        return str == null || str.trim().isEmpty();
    }



    /**
     * 查询产品是否存在，如果存在则返回ID，如果不存在则新增并返回新生成的ID
     * @param productName 产品名称
     * @param currentUser 当前操作用户
     * @return 产品ID
     */
    @Transactional(rollbackFor = Exception.class)
    public Long getOrCreateProductByName(String productName, String currentUser) {
        try {
            // 1. 查询产品是否已存在
            QueryWrapper<ProductEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq(ProductEntity::getName, productName);

            ProductEntity existingProduct = productMapper.selectOne(queryWrapper);

            // 2. 如果产品存在，直接返回ID
            if (existingProduct != null) {
                return existingProduct.getId();
            }

            // 3. 如果产品不存在，创建新产品
            ProductEntity newProduct = new ProductEntity();
            newProduct.setId(getSnowflakeId());
            newProduct.setName(productName);
            newProduct.setCreatedBy(currentUser);
            newProduct.setUpdatedBy(currentUser);
            newProduct.setCreatedTime(LocalDateTime.now());
            newProduct.setUpdatedTime(LocalDateTime.now());

            // 4. 插入新产品
            int result = productMapper.insert(newProduct);

            // 5. 检查插入是否成功
            if (result > 0) {
                return newProduct.getId();
            } else {
                throw new RuntimeException("创建产品失败");
            }
        } catch (Exception e) {
            log.error("查询或创建产品时发生错误，产品名称: {}", productName, e);
            throw new RuntimeException("操作产品失败: " + e.getMessage());
        }
    }

    /**
     * 根据参数判断是否已存在productFlow，如果存在返回ID，如果不存在则完成插入操作
     *
     * @param name 名称
     * @param type 类型
     * @param location 位置
     * @param referenceFlowProperty 参考流属性
     * @param currentUser 当前操作用户
     */
    @Transactional(rollbackFor = Exception.class)
    public Long getOrCreateProductFlow(String name, Long type, Long location,String serialNumber,
                                       Long referenceFlowProperty, String currentUser) {
        // 1. 查询是否已存在相同的productFlow
        // 先根据name, type, location查询所有符合条件的productFlow
        QueryWrapper<ProductFlowEntity> flowQueryWrapper = new QueryWrapper<>();

        flowQueryWrapper.lambda()
                .eq(StringUtils.isNotBlank(name),ProductFlowEntity::getName, name)
                .eq(null!=type,ProductFlowEntity::getType, type)
                .eq( null!=location,ProductFlowEntity::getLocation, location)
                .eq(StringUtils.isNotBlank(serialNumber), ProductFlowEntity::getSerialNumber, serialNumber);

        List<ProductFlowEntity> productFlows = productFlowMapper.selectList(flowQueryWrapper);

        // 在这些结果中查找referenceFlowProperty关联的ProductFlowProperty记录中
        // flowProperty字段等于参数referenceFlowProperty的记录
        for (ProductFlowEntity flow : productFlows) {
            Long referenceFlowPropertyId = flow.getReferenceFlowProperty();
            if (referenceFlowPropertyId != null) {
                // 查询对应的ProductFlowProperty记录
                QueryWrapper<ProductFlowPropertyEntity> propertyQueryWrapper = new QueryWrapper<>();
                propertyQueryWrapper.lambda()
                        .eq(ProductFlowPropertyEntity::getId, referenceFlowPropertyId)
                        .eq(ProductFlowPropertyEntity::getFlowProperty, referenceFlowProperty);

                ProductFlowPropertyEntity flowProperty = productFlowPropertyMapper.selectOne(propertyQueryWrapper);
                if (flowProperty != null) {
                    // 找到符合条件的记录，直接返回ID
                    return flow.getId();
                }
            }
        }

        try {
            // 2. 不存在则需要插入新的记录
            LocalDateTime now = LocalDateTime.now();
            long productFlowId = getSnowflakeId();
            long productFlowPropertyId = getSnowflakeId();

            // 3. 先插入ProductFlow（referenceFlowProperty字段暂时设置为传入的参数）
            ProductFlowEntity productFlow = new ProductFlowEntity();
            productFlow.setRefId(UUID.randomUUID().toString());
            productFlow.setId(productFlowId);
            productFlow.setName(name);
            productFlow.setType(type);
            productFlow.setLocation(location);
            productFlow.setReferenceFlowProperty(referenceFlowProperty); // 临时设置
            productFlow.setCreatedBy(currentUser);
            productFlow.setUpdatedBy(currentUser);
            productFlow.setCreatedTime(now);
            productFlow.setUpdatedTime(now);
            productFlow.setSerialNumber(serialNumber);
            productFlow.setReferenceFlowProperty(productFlowPropertyId);

            productFlowMapper.insert(productFlow);


            // 4. 插入ProductFlowProperty

            ProductFlowPropertyEntity productFlowProperty = new ProductFlowPropertyEntity();
            productFlowProperty.setId(productFlowPropertyId);
            productFlowProperty.setFlow(productFlowId); // 关联新插入的ProductFlow ID
            productFlowProperty.setFlowProperty(referenceFlowProperty); // 使用传入的参数
            productFlowProperty.setConversionFactor(BigDecimal.ONE); // 设置为1
            productFlowProperty.setIsDefault(true); // 可以根据业务需要设置默认值
            productFlowProperty.setCreatedBy(currentUser);
            productFlowProperty.setUpdatedBy(currentUser);
            productFlowProperty.setCreatedTime(now);
            productFlowProperty.setUpdatedTime(now);

            productFlowPropertyMapper.insert(productFlowProperty);

            // 5. 返回ProductFlow的ID
            return productFlowId;
        } catch (Exception e) {
            log.error("创建ProductFlow和ProductFlowProperty时发生错误", e);
            throw new RuntimeException("创建流程失败: " + e.getMessage());
        }
    }

    /**
     * 创建产品过程实体
     *
     * @param name 名称
     * @param product 产品ID
     * @param flow 流程ID
     * @param location 位置
     * @param description 描述
     * @param currentUser 当前操作用户
     * @return 创建的ProductProcessEntity
     */
    @Transactional(rollbackFor = Exception.class)
    public ProductProcessEntity createProductProcess(String name, Long product, Long flow,
                                                     Long location, String description, String currentUser) {
        try {
            // 创建产品过程实体
            ProductProcessEntity productProcess = new ProductProcessEntity();

            // 设置基本属性
            productProcess.setId(getSnowflakeId());
            productProcess.setName(name);
            productProcess.setProduct(product);
            productProcess.setFlow(flow);
            productProcess.setLocation(location);
            productProcess.setDescription(description);

            // 设置特殊属性
            productProcess.setRefId(UUID.randomUUID().toString()); // UUID生成
            productProcess.setVersion(System.currentTimeMillis()); // 当前时间戳
            productProcess.setIsLatestOne(1); // 设置为最新版本

            // 设置审计字段
            productProcess.setCreatedBy(currentUser);
            productProcess.setUpdatedBy(currentUser);
            productProcess.setCreatedTime(LocalDateTime.now());
            productProcess.setUpdatedTime(LocalDateTime.now());

            // 插入数据库
            this.save(productProcess);

            return productProcess;
        } catch (Exception e) {
            log.error("创建产品过程时发生错误，名称: {}", name, e);
            throw new RuntimeException("创建产品过程失败: " + e.getMessage());
        }
    }

    /**
     * 根据名称查询ProductFlowType，返回第一个匹配记录的ID（简洁版）
     *
     * @param name 分类名称
     * @return ProductFlowType的ID，如果未找到则返回null
     */
    public Long getProductFlowTypeIdByName(String name) {
        ProductFlowTypeEntity entity = productFlowTypeMapper.selectOne(
                new QueryWrapper<ProductFlowTypeEntity>()
                        .lambda()
                        .eq(ProductFlowTypeEntity::getName, name)
        );
        return entity != null ? entity.getId() : null;
    }

    /**
     * 获取Exchange数据
     *
     * @param currentFlow 当前流程
     * @param currentUser 当前用户
     */
    public ProductExchangeEntity getExchangeData(Long processId, Map<String, String> currentFlow, String currentUser) {

        var db = DataDir.get().openDatabase(DerbyConfig.DBNAME);

        String mainProductName = currentFlow.get("name");
        long type = 0L;
        FlowProperty flowProperty = new FlowProperty();
        long flowPropertyId = 0L;
        long flowId = 0L;
        long providerId = 0L;
        boolean isInput = true;
        boolean isProduct = true;
        long unitId = 0L;
        String productType = "";
        BigDecimal partitionCoefficient = BigDecimal.ONE;
        Long providerType = null;
        long productFlowType = 1L;
        Long parentId = null;

        // allocation_factor判空和非数字保护
        if ("产品".equals(currentFlow.get("io_type"))) {
            isInput = false;
            isProduct = true;
            productType = currentFlow.get("type");
            String allocationFactorStr = currentFlow.get("allocation_factor");
            if (allocationFactorStr != null) {
                try {
                    partitionCoefficient = new BigDecimal(allocationFactorStr);
                } catch (Exception e) {
                    partitionCoefficient = BigDecimal.ONE;
                }
            } else {
                partitionCoefficient = BigDecimal.ONE;
            }
        } else if ("输入".equals(currentFlow.get("io_type"))) {
            isInput = true;
            isProduct = false;
        } else if ("输出".equals(currentFlow.get("io_type"))) {
            isInput = false;
            isProduct = false;
        }

        if ("用户数据库".equals(currentFlow.get("source"))) {
            type = getProductFlowTypeIdByName(currentFlow.get("category").trim()) != null ? getProductFlowTypeIdByName(currentFlow.get("category").trim()) : 0L;
            FlowPropertyDao flowPropertyDao = new FlowPropertyDao(db);
            var flowPropertyList = flowPropertyDao.getForName(currentFlow.get("unit_group"));
            if (flowPropertyList != null && !flowPropertyList.isEmpty()) {
                flowProperty = flowPropertyList.getFirst();
                flowPropertyId = flowProperty.id;
                if (flowProperty.getReferenceUnit() != null) {
                    unitId = flowProperty.getReferenceUnit().id;
                }
            }
            Long locationId = null;
            if(null!= currentFlow.get("location_code")){
                locationId = productProcessMapper.getGlobalRegions(currentFlow.get("location_code"));
            }
            flowId = getOrCreateProductFlow(mainProductName, type, locationId, currentFlow.get("number"), flowPropertyId, currentUser);
            productFlowType = 1L;
        } else if ("背景数据集".equals(currentFlow.get("source"))) {
            String category = currentFlow.get("environmental_flow_category") != null ? currentFlow.get("environmental_flow_category") : "";
            Category category1 = new CategoryDao(db).getForPath(ModelType.FLOW, category);
            long id = category1 != null ? category1.id : 0L;
            List<Flow> flowList = new FlowDao(db).getForName(currentFlow.get("name"));
            Flow flow = null;
            if (flowList != null && !flowList.isEmpty()) {
                flow = flowList.stream()
                        .filter(flow1 -> flow1.category != null && flow1.category.id == id)
                        .findFirst().orElse(null);
            }
            if (flow != null) {
                flowId = flow.id;
            }
            FlowPropertyDao flowPropertyDao = new FlowPropertyDao(db);
            var flowPropertyList = flowPropertyDao.getForName("Mass");
            if (flowPropertyList != null && !flowPropertyList.isEmpty()) {
                flowProperty = flowPropertyList.getFirst();
                flowPropertyId = flowProperty.id;
                if (flowProperty.getReferenceUnit() != null) {
                    unitId = flowProperty.getReferenceUnit().id;
                }
            }
            productFlowType = 0L;
        }

        if ("输入".equals(currentFlow.get("io_type")) || "输出".equals(currentFlow.get("io_type"))) {
            if ("用户数据库".equals(currentFlow.get("source"))) {
                if ("系统已有工序".equals(currentFlow.get("upstream_type"))) {
                    String provider = currentFlow.get("process_name");
                    QueryWrapper<ProductEntity> queryWrapper = new QueryWrapper<>();
                    queryWrapper.lambda().eq(ProductEntity::getName, currentFlow.get("product_name"));
                    ProductEntity existingProduct = productMapper.selectOne(queryWrapper);
                    long productId = 0L;
                    if (existingProduct != null) {
                        productId = existingProduct.getId();
                    }
                    ProductProcessEntity productProcess = productProcessMapper.selectOne(
                            new QueryWrapper<ProductProcessEntity>()
                                    .lambda()
                                    .eq(ProductProcessEntity::getName, provider)
                                    .eq(0L != productId, ProductProcessEntity::getProduct, productId)
                    );
                    if (productProcess != null) {
                        providerId = productProcess.getId();
                        providerType = 1L;
                    }
                } else if ("背景数据集".equals(currentFlow.get("upstream_type"))) {

                    String provicer = null!=currentFlow.get("background_name")? currentFlow.get("background_name").trim():"";
                    String providerLocation = null!=currentFlow.get("country_code")? currentFlow.get("country_code").trim():"";
//                    List<Process> processList = new ProcessDao(db).getForName(provicer);
                    List<GetProviderInfo> providerInfo = productProcessMapper.getProviderInfo(provicer, providerLocation);
                    if(!providerInfo.isEmpty()){
                        providerId = providerInfo.getFirst().getId();
                    }
//                    Process process = null;
//                    if (processList != null && !processList.isEmpty()) {
//                        process = processList.stream()
//                                .filter(process1 -> process1.location != null && process1.location.code.equals(providerLocation))
//                                .findFirst().orElse(null);
//                    }
//                    if (process != null) {
//                        providerId = process.id;
//                    }
                    providerType = 0L;
                }
            }
        }

        if ("主产品".equals(currentFlow.get("type"))) {
            parentId = 0L;
        }

        ProductExchangeEntity mainProductExchangeEntity = new ProductExchangeEntity()
                .setId(getSnowflakeId())
                .setProductFlow(flowId)
                .setProductProcess(processId)
                .setIsInput(isInput)
                .setIsProduct(isProduct)
                .setProductType(productType)
                .setPartitionCoefficient(partitionCoefficient)
                .setUnit(unitId)
                .setParentId(parentId)
                .setFlowProperty(flowPropertyId)
                .setProductFlowType(productFlowType)
                .setProvider(providerId)
                .setProviderType(providerType)
                .setCreatedTime(LocalDateTime.now())
                .setUpdatedTime(LocalDateTime.now())
                .setCreatedBy(currentUser)
                .setUpdatedBy(currentUser);

        return mainProductExchangeEntity;
    }

    /**
     * 批量插入产品交换实体列表（优化版）
     *
     * @param exchangeEntityList 产品交换实体列表
     * @return 插入成功的记录数
     */
    @Transactional(rollbackFor = Exception.class)
    public void batchInsertProductExchanges(List<ProductExchangeEntity> exchangeEntityList) {
        try {
            // 使用指定批次大小的批量插入方法
            productExchangeMapper.insert(exchangeEntityList);
        } catch (Exception e) {
            log.error("批量插入产品交换记录时发生错误，记录数: {}", exchangeEntityList.size(), e);
            throw new RuntimeException("批量插入失败: " + e.getMessage());
        }
    }

    /**
     * 使用雪花算法生成16为的id
     */
    public Long getSnowflakeId() {
        Snowflake snowflake = IdUtil.getSnowflake(1, 1);
        long id = snowflake.nextId();
        // 固定16位
//        return id;
        return id % 10000000000000000L;
    }

    /**
     *
     * 根据传入的 set<Long>类型的参数，生成16位ID并返回Map<Long,Long>类型的返回值
     */
    public Map<Long,Long> getSnowflakeId(Set<Long> args) {
        return args.stream().map(arg -> {
            long id = getSnowflakeId(); // 生成16位ID
            return Map.entry(arg, id); // 返回一个包含参数和ID的映射
        }).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
    }

    /**
     * 根据传入的 set<Long>类型的参数，生成UUID并返回Map<Long,String>类型的返回值
     * @param args
     */
    public Map<Long,String> getUUID(Set<Long> args) {
        return args.stream().map(arg -> {
            String uuid = java.util.UUID.randomUUID().toString(); // 生成UUID
            return Map.entry(arg, uuid); // 创建一个包含参数和UUID的映射
        }).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
    }

    /**
     * 获取位置的 id
     */
    public Long getLocationId(String location) {
        Long locationId = null;
        if(location != null && !location.isEmpty()){
            locationId = productProcessMapper.getGlobalRegions( location);
            if(null!=locationId){
                return locationId;
            }else{
                locationId = productProcessMapper.gettblLocations(location);
                if(null!=locationId){
                    return locationId;
                }else{
                    return null;
                }
            }
        }
        return null;
    }

    @Override
    public GetTaskReportEntities getTaskReportEntities(Long taskId) {
        
        // 查询所有的 flow
        QueryWrapper<TaskReportEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(TaskReportEntity::getTask, taskId);
        List<TaskReportEntity> taskReportEntity = taskReportMapper.selectList(queryWrapper);

        // 获取所有的 process id 和 非背景数据库的flowid 并生成新的 id 和 refId
        Set<Long> processIdSet = taskReportEntity.stream().map(TaskReportEntity::getProductProcessId).collect(Collectors.toSet());
        // 只有本地数据库的数据进行替换 id 和 ref 的操作
        Set<Long> flowIdSet = taskReportEntity.stream().filter(t->t.getProductFlowType()==1).map(TaskReportEntity::getProductFlowId).collect(Collectors.toSet());
        Map<Long, Long> processIdMap = this.getSnowflakeId(processIdSet);
        Map<Long, Long> flowIdMap = this.getSnowflakeId(flowIdSet);
        Map<Long, String> processIdRefIdMap = this.getUUID(processIdSet);
        Map<Long, String> flowIdRefIdMap = this.getUUID(flowIdSet);

        // 替换taskReportEntity中所有的 processid、flowid、refId
         taskReportEntity.forEach(t -> {
             t.setTblFlowId(t.getProductFlowType() == 1 ? flowIdMap.get(t.getProductFlowId()):t.getProductFlowId());
             t.setTblProcessId(processIdMap.get(t.getProductProcessId()));
             t.setTblFlowRefId(flowIdRefIdMap.get(t.getProductFlowId()));
             t.setTblProcessRefId(processIdRefIdMap.get(t.getProductProcessId()));
             if(null!= t.getProviderType()){
                 t.setTblProviderId( t.getProviderType() == 1 ? processIdMap.get(t.getProviderId()):t.getProviderId());
             }
         });

        List<GetRequestProcessInfo> getRequestProcessInfoList = taskReportMapper.getRequestProcessInfo(taskId);
        // 替换processId、refId、flowId、refId
        getRequestProcessInfoList.forEach(t -> {
            t.setTblFlowId(flowIdMap.get(t.getProductFlowId()));
            t.setTblProcessId(processIdMap.get(t.getProductProcessId()));
            t.setTblFlowRefId(flowIdRefIdMap.get(t.getProductFlowId()));
            t.setTblProcessRefId(processIdRefIdMap.get(t.getProductProcessId()));
        });

        // 获取新的 processid
        TaskReportEntity taskReport= taskReportEntity.stream().filter(t -> t.getLevel()==1 && t.getIsMainProduct()==true).findFirst().orElse(null);

        return new GetTaskReportEntities().setGetTaskReportEntities(taskReportEntity).setGetRequestProcessInfoList(getRequestProcessInfoList).setNewProcessId(null!=taskReport?taskReport.getTblProcessId():null);
    }

    @Override
    public List<FlowRequest> getFlowRequests(List<TaskReportEntity> taskReportEntity) {

        // 筛选出所有的 flow
        // 获取 主 process 的主产品 flow
        TaskReportEntity taskReportEntityMainFlow = taskReportEntity.stream().filter(t -> t.getLevel()==1&&t.getIsMainProduct()==true).findFirst().orElse(null);
        // 获取所有的非主产品的 flow（去重）
        List<TaskReportEntity> taskReportEntityFlow = new ArrayList<>(taskReportEntity.stream().filter(t -> t.getProductFlowType().equals(1) && t.getIsMainProduct() == false).toList());
        taskReportEntityFlow.add(taskReportEntityMainFlow);
        // 获取其他 process 的主产品
        List<TaskReportEntity>  otherPrcessMainFlow = taskReportEntity.stream().filter(t -> t.getLevel()!=1&&t.getIsMainProduct()==true).toList();
        taskReportEntityFlow.addAll(otherPrcessMainFlow);

        return taskReportEntityFlow.stream()
        .map(tr -> {
            FlowRequest flowRequest = new FlowRequest();
            flowRequest.setId(tr.getTblFlowId());
            flowRequest.setRefId(tr.getTblFlowRefId());
            flowRequest.setName(tr.getProductFlowName());
            flowRequest.setFlowPropertyId(tr.getFlowProperty());
            Map<Long,Double> propertyFators = new HashMap<>();
            propertyFators.put(tr.getFlowProperty(),tr.getConversionFactor());
            flowRequest.setPropertyFators(propertyFators);
            return flowRequest;
        }).toList();
    }

    @Override
    public List<ProcessRequest> getProcessRequests(List<TaskReportEntity> taskReportEntity, List<GetRequestProcessInfo> getRequestProcessInfoList) {

        // 组装 process
                 return getRequestProcessInfoList.stream()
                .map(tr -> {
                    ProcessRequest processRequest = new ProcessRequest();
                    processRequest.setId(tr.getTblProcessId());
                    processRequest.setName(tr.getProductProcessName());
                    processRequest.setFlowId(tr.getTblFlowId());
                    processRequest.setRefId(tr.getTblProcessRefId());

                    processRequest.setInputIds(
                            taskReportEntity.stream()
                                    .filter(t->t.getProductProcessId().equals(tr.getProductProcessId()) && t.getIsInput() == true)
                                    .map(t->{
                                        ExchangeRequest exchangeRequest = new ExchangeRequest();
                                        exchangeRequest.setFlowId(t.getTblFlowId());
                                        exchangeRequest.setDefaultProviderId(t.getTblProviderId());
                                        exchangeRequest.setFlowRefId( t.getTblFlowRefId() );
                                        exchangeRequest.setAmount(t.getAmount() != null ? t.getAmount().doubleValue():0);
                                        exchangeRequest.setPropertyId(t.getFlowProperty());
                                        exchangeRequest.setUnitId(t.getUnit());
                                        return exchangeRequest;
                                    })
                                    .toList());
                    processRequest.setOutputIds(
                            taskReportEntity.stream()
                                    .filter(t->t.getProductProcessId().equals(tr.getProductProcessId()) && t.getIsInput() == false)
                                    .map(t->{
                                        ExchangeRequest exchangeRequest = new ExchangeRequest();
                                        exchangeRequest.setFlowId(t.getTblFlowId());
                                        exchangeRequest.setDefaultProviderId(t.getTblProviderId());
                                        exchangeRequest.setFlowRefId( t.getTblFlowRefId() );
                                        if(null!=t.getAmount()){
                                            exchangeRequest.setAmount(t.getAmount().multiply(null!=t.getPartitionCoefficient() ? t.getPartitionCoefficient(): BigDecimal.valueOf(1.00)).doubleValue());
                                        }
                                        exchangeRequest.setPropertyId(t.getFlowProperty());
                                        exchangeRequest.setUnitId(t.getUnit());
                                        return exchangeRequest;
                                    })
                                    .toList());
                    return processRequest;
                }).toList();

    }

    Process saveProcess(ProcessRequest request, Derby db,Location  location) {
        Process process = Process.of(
                request.getName(),
                db.get(Flow.class, request.getFlowId())
        );
        process.id = request.getId();
        process.refId = request.getRefId();
        process.location = new LocationDao( db).getForId(6153L);

        if (StringUtils.isNotBlank(request.getLocationRefId())) {
            process.location = db.get(Location.class, request.getLocationRefId());
        }
        if (StringUtils.isNotBlank(request.getDescription())) {
            process.description = request.getDescription();
        }
        process.processType = request.getProcessType();
        process.defaultAllocationMethod = request.getDefaultAllocationMethod();
        process.infrastructureProcess = request.getInfrastructureProcess();
        if (request.getLastInternalId() != null) {
            process.lastInternalId = request.getLastInternalId();
        }
        if (StringUtils.isNotBlank(request.getDqEntry())) {
            process.dqEntry = request.getDqEntry();
        }

        if (StringUtils.isNotBlank(request.getQuantitativeReferenceFlowRefId())) {
            process.quantitativeReference = Exchange.input(
                    db.get(Flow.class, request.getQuantitativeReferenceFlowRefId()),
                    request.getQuantitativeReferenceAmount()
            );
        }

        if (null != request.getInputIds()) {
            request.getInputIds().forEach((exchangeRequest) -> {
                var unitdao = new UnitDao(db);
                Exchange inputExchange = Exchange.of(db.get(Flow.class, exchangeRequest.getFlowId()), db.get(FlowProperty.class, exchangeRequest.getPropertyId()), unitdao.getForId(exchangeRequest.getUnitId()));
                inputExchange.amount = exchangeRequest.getAmount();
                inputExchange.isInput = true;

                // 修改不确定性为 正态分布（Normal）
                inputExchange.uncertainty = Uncertainty.normal(exchangeRequest.getAmount(), exchangeRequest.getAmount() * 0.05);
                log.info("inputExchange set uncertainty:{}", exchangeRequest.getAmount() * 0.05);

                if (exchangeRequest.getDefaultProviderId() != null) {
                    if (exchangeRequest.getDefaultProviderId() >0 && exchangeRequest.getDefaultProviderId() <= 63763210 ) {
                        log.info("当前请求的是：{}",JSONUtil.toJsonStr(exchangeRequest));
                        Flow inputFlow = db.get(Process.class, exchangeRequest.getDefaultProviderId()).quantitativeReference.flow;
                        // 新建一个process，quantitativeReference是当前的输入输出项
                        Process exchangeRequestProcess = Process.of(
                                inputExchange.flow.name + UUID.randomUUID().toString(),
                                db.get(Flow.class, exchangeRequest.getFlowId())
                        );
                        // input 设置为 inputFlow , provider 是 exchangeRequest.getDefaultProviderId();
                        Exchange exchangeRequestProcessInput = Exchange.input(inputFlow, 1);
                        exchangeRequestProcessInput.defaultProviderId = exchangeRequest.getDefaultProviderId();
                        // input 设置为 inputFlow , provider 是 exchangeRequest.getDefaultProviderId();
                        // 修改 当前的process 的 default Provider 为 新建的processid
                        exchangeRequestProcess.add(exchangeRequestProcessInput);

                        var dao = new ProcessDao(db);
                        inputExchange.defaultProviderId = dao.insert(exchangeRequestProcess).id;
                    } else {
                        inputExchange.defaultProviderId = exchangeRequest.getDefaultProviderId();
                    }
                }
                process.add(inputExchange);
            });
        }

        if (null != request.getOutputIds()) {
            request.getOutputIds().forEach((exchangeRequest -> {

                //判断主产品
                if (!exchangeRequest.getFlowId().equals(request.getFlowId())) {
                    log.info("当前执行的outputId是{}，请求参数的flowId是{}", exchangeRequest.getFlowId(), request.getFlowId());
                    var unitdao = new UnitDao(db);
                    Exchange outputExchange = Exchange.of(db.get(Flow.class, exchangeRequest.getFlowId()), db.get(FlowProperty.class, exchangeRequest.getPropertyId()), unitdao.getForId(exchangeRequest.getUnitId()));
                    outputExchange.amount = exchangeRequest.getAmount();
                    outputExchange.isInput = false;
                    if (exchangeRequest.getDefaultProviderId() != null) {
                        outputExchange.defaultProviderId = exchangeRequest.getDefaultProviderId();
                    }

                    // 修改不确定性为 正态分布（Normal）
                    outputExchange.uncertainty = Uncertainty.normal(exchangeRequest.getAmount(), exchangeRequest.getAmount() * 0.05);
                    log.info("outputExchange set uncertainty:{}", exchangeRequest.getAmount() * 0.05);

                    process.add(outputExchange);
                } else {
                    var unitdao = new UnitDao(db);
                    if(null==process.quantitativeReference){
                        log.info("当前执行的outputId是{}，请求参数的flowId是{}", exchangeRequest.getFlowId(), request.getFlowId());
                    }
                    process.quantitativeReference.amount = exchangeRequest.getAmount();
                    process.quantitativeReference.unit = unitdao.getForId(exchangeRequest.getUnitId());
                    process.quantitativeReference.flowPropertyFactor = process.quantitativeReference.flow.getFactor(db.get(FlowProperty.class, exchangeRequest.getPropertyId()));
                    if (exchangeRequest.getDefaultProviderId() != null) {
                        process.quantitativeReference.defaultProviderId = exchangeRequest.getDefaultProviderId();
                    }
                }
            }));
        }


        // 持久化到数据库
        var dao = new ProcessDao(db);
        dao.insert(process);
        return process;
    }

    void addFlowBatch(List<FlowRequest> requestList,Derby db){
        log.info(JSONUtil.toJsonStr(requestList));


        requestList.forEach(request -> {
            Flow flow = Flow.product(
                    request.getName(),
                    db.get(FlowProperty.class, request.getFlowPropertyId())
            );

            flow.id = request.getId();
            flow.refId = request.getRefId();
            if (request.getInfrastructureFlow() != null) {
                flow.infrastructureFlow = request.getInfrastructureFlow();
            }
            if (StringUtils.isNotBlank(request.getDescription())) {
                flow.description = request.getDescription();
            }
            if (StringUtils.isNotBlank(request.getCasNumber())) {
                flow.casNumber = request.getCasNumber();
            }
            if (StringUtils.isNotBlank(request.getLocationRefId())) {
                flow.location = db.get(Location.class, request.getLocationRefId());
            }
            if (StringUtils.isNotBlank(request.getFormula())) {
                flow.formula = request.getFormula();
            }
            if (StringUtils.isNotBlank(request.getSynonyms())) {
                flow.synonyms = request.getSynonyms();
            }

            request.getPropertyFators().forEach((k, v) -> {
                if (!Objects.equals(k, request.getFlowPropertyId())) {
                    flow.flowPropertyFactors.add(FlowPropertyFactor.of(db.get(FlowProperty.class, k), v));
                } else {
                    flow.getFactor(db.get(FlowProperty.class, k)).conversionFactor = v;
                }
            });

            // 持久化到数据库
            var dao = new FlowDao(db);
            dao.insert(flow);
        });

    }

    @Override
    public GlobalResponse<Boolean> addProcessTree(Long taskId) {
        GetTaskReportEntities getTaskReportEntities = this.getTaskReportEntities(taskId);
        List<TaskReportEntity> taskReportEntity = getTaskReportEntities.getGetTaskReportEntities().stream()
                .collect(Collectors.toMap(
                        TaskReportEntity::getTblFlowId, // 以 tblFlowId 作为 key
                        e -> e,                         // value 就是当前对象
                        (e1, e2) -> e1                  // 如果 key 重复，保留第一个
                ))
                .values()
                .stream()
                .toList();
        List<FlowRequest> flowRequestList = this.getFlowRequests(taskReportEntity);
        List<ProcessRequest> processRequestList = this.getProcessRequests(getTaskReportEntities.getGetTaskReportEntities(),getTaskReportEntities.getGetRequestProcessInfoList());
        log.info("flow 请求 json:{}", JSONUtil.toJsonStr(flowRequestList));
        log.info("process 请求 json:{}", JSONUtil.toJsonStr(processRequestList));
        try (var db = DataDir.get().openDatabase(DerbyConfig.DBNAME)){
            // 插入到 flow
            this.addFlowBatch(flowRequestList,db);
            Location location = new LocationDao( db).getForId(6153L);
            // 插入到 process
            processRequestList.forEach(request -> saveProcess(request, db, location));
            db.close();

            //使用 mybatis-plus 批量修改 taskReport的数据，参数是flowRequestList
            taskReportMapper.updateById(getTaskReportEntities.getGetTaskReportEntities());

            TaskEntity taskEntity = new TaskEntity();
            taskEntity.setId(taskId).setNewProcessId(getTaskReportEntities.getNewProcessId());
            taskMapper.updateById(taskEntity);

            return GlobalResponse.of( true);
        }catch (Exception e){
            log.error("ProductProcessServiceImpl#addProcessTree error",e);
        }

        return GlobalResponse.of( false);
    }

    @Override
    public GlobalResponse<Boolean> addTree(GetProcessTreeData getProcessTreeData) {
        List<FlowRequest> flowRequestList = getProcessTreeData.getFlowRequestList();
        ProcessRequest processRequestList = getProcessTreeData.getProcessRequest();
        try (var db = DataDir.get().openDatabase(DerbyConfig.DBNAME)) {
            // 插入到 flow
            addFlowBatch(flowRequestList, db);
            Location location = new LocationDao( db).getForId(6153L);
            // 插入到 process
            saveProcess(processRequestList, db, location);
            db.close();
            return GlobalResponse.of( true);
        }catch (Exception e){
            log.error("ProductProcessServiceImpl#addProcessTree error",e);
        }
        return GlobalResponse.of( false);
    }
}
